#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define READER_COUNT 3  // 读者数量
#define WRITER_COUNT 2  // 写者数量
#define MAX_LOOP 3      // 每个线程循环次数

// 颜色定义
#define COLOR_RESET   "\033[0m"
#define COLOR_READER  "\033[34m"  // 蓝色表示读者
#define COLOR_WRITER  "\033[31m"  // 红色表示写者

// 简化的共享数据结构
typedef struct {
    int value;           // 数据值
    int write_count;     // 总写入次数
    int last_writer_id;  // 最后写入的写者ID
} shared_data_t;

shared_data_t shared_data = {0, 0, 0};  // 共享数据
int reader_count = 0;   // 当前读者数量

sem_t rw_mutex;         // 用于写者与其他读者/写者互斥
sem_t mutex;            // 用于对reader_count的互斥访问

// 读者线程函数
void *reader(void *arg) {
    int id = *(int *)arg;
    
    for (int i = 0; i < MAX_LOOP; i++) {
        sem_wait(&mutex);           // 进入临界区保护reader_count
        reader_count++;             // 增加读者计数
        if (reader_count == 1) {    // 如果是第一个读者
            sem_wait(&rw_mutex);    // 阻止写者进入
        }
        sem_post(&mutex);           // 退出临界区

        // 读取共享数据 - 使用蓝色输出
        printf(COLOR_READER "读者 %d 正在读数据: 值=%d, 总写入次数=%d, 最后写入者=%d" COLOR_RESET "\n", 
               id, shared_data.value, shared_data.write_count, 
               shared_data.last_writer_id);
        sleep(1);  // 模拟读取耗时

        sem_wait(&mutex);           // 进入临界区保护reader_count
        reader_count--;             // 减少读者计数
        if (reader_count == 0) {    // 如果是最后一个读者
            sem_post(&rw_mutex);    // 允许写者进入
        }
        sem_post(&mutex);           // 退出临界区

        sleep(1);  // 模拟下次读取间隔
    }
    pthread_exit(NULL);
}

// 写者线程函数
void *writer(void *arg) {
    int id = *(int *)arg;
    
    for (int i = 0; i < MAX_LOOP; i++) {
        sem_wait(&rw_mutex);        // 加锁，确保只有一个写者写入

        // 写入共享数据 - 更新所有字段
        shared_data.value = id * 100 + (i + 1);  // 生成唯一值: 写者ID*100 + 序列号
        shared_data.write_count++;
        shared_data.last_writer_id = id;
        
        printf(COLOR_WRITER "写者 %d 正在写数据: 新值=%d (第%d次写入，总第%d次写入)" COLOR_RESET "\n", 
               id, shared_data.value, i + 1, shared_data.write_count);
        sleep(2);  // 模拟写入耗时

        sem_post(&rw_mutex);        // 解锁，允许其他读者/写者访问

        sleep(1);  // 模拟下次写入间隔
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t readers[READER_COUNT], writers[WRITER_COUNT];
    int reader_ids[READER_COUNT], writer_ids[WRITER_COUNT];

    printf("=== 读者-写者问题演示开始 ===\n");
    printf("共享数据初始状态: 值=%d, 总写入次数=%d, 最后写入者=%d\n\n", 
           shared_data.value, shared_data.write_count, shared_data.last_writer_id);

    // 初始化信号量
    sem_init(&rw_mutex, 0, 1);  // 初始值为1，表示允许一个写者或多个读者
    sem_init(&mutex, 0, 1);     // 初始值为1，用于互斥访问reader_count

    // 创建读者线程
    for (int i = 0; i < READER_COUNT; i++) {
        reader_ids[i] = i + 1;
        pthread_create(&readers[i], NULL, reader, &reader_ids[i]);
    }

    // 创建写者线程
    for (int i = 0; i < WRITER_COUNT; i++) {
        writer_ids[i] = i + 1;
        pthread_create(&writers[i], NULL, writer, &writer_ids[i]);
    }

    // 等待所有读者线程结束
    for (int i = 0; i < READER_COUNT; i++) {
        pthread_join(readers[i], NULL);
    }

    // 等待所有写者线程结束
    for (int i = 0; i < WRITER_COUNT; i++) {
        pthread_join(writers[i], NULL);
    }

    // 销毁信号量
    sem_destroy(&rw_mutex);
    sem_destroy(&mutex);

    printf("\n=== 所有读者和写者都已完成 ===\n");
    printf("共享数据最终状态: 值=%d, 总写入次数=%d, 最后写入者=%d\n", 
           shared_data.value, shared_data.write_count, shared_data.last_writer_id);
    printf("程序结束。\n");
    
    return 0;
}